﻿using DataLayer;
using DataLayer.BD;
using SupportLayer.Constantes.PRODUTO;
using SupportLayer.Constantes.Tabelas;
using SupportLayer.Enums;
using SupportLayer.Objetos.Produto;
using SupportLayer.ExtensionMethods;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BusinessLayer
{
	public class Produto
	{
		Dictionary<string, object> parametros = new Dictionary<string, object>();

		#region Categorias
		public int InsertCategoria(CategoriaClass Categoria)
		{
			try
			{
				return new DataAccess().Insert(Categoria, CATEGORIA.ID, TABELAS.CATEGORIA);
			}
			catch (Exception)
			{
				throw;
			}
		}
		public CategoriaClass SelectCategoria(int CategoriaID)
		{
			parametros = new Dictionary<string, object>();
			parametros.Add(CATEGORIA.ID, CategoriaID);

			return new DataAccess().Select(new CategoriaClass(), TABELAS.CATEGORIA, new string[] { "*" }, parametros).toCategoriaClass()[0];
		}
		public List<CategoriaClass> GetCategorias()
		{
			try
			{
				return new DataAccess().Select(new CategoriaClass(), TABELAS.CATEGORIA, new string[] { "*" }, null).toCategoriaClass();
			}
			catch (Exception)
			{
				throw;
			}
		}
		public void UpdateCategoria(CategoriaClass Categoria)
		{
			Dictionary<string, object> set = new Dictionary<string, object>();
			parametros = new Dictionary<string, object>();

			set.Add(CATEGORIA.DESCRICAO, Categoria.Descricao);
			set.Add(CATEGORIA.TAGS, Categoria.Tags);

			parametros.Add(CATEGORIA.ID, Categoria.ID);

			new DataAccess().Update(Categoria, TABELAS.CATEGORIA, set, parametros);
		}
		public void DeleteCategoria(int CategoriaID)
		{
			try
			{
				new DataAccess().Delete(TABELAS.CATEGORIA, CATEGORIA.ID, CategoriaID);
			}
			catch (Exception)
			{
				throw;
			}
		}
		#endregion
		#region Categoria Master
		public List<CategoriaMasterClass> GetCateroriaMaster()
		{
			return new DataAccess().Select(new CategoriaMasterClass(), TABELAS.CATEGORIA_MASTER, new string[] { "*" }, null).toCategoriaMasterClass();
		}
		#endregion
		#region Destaques
		public int InsertDestaque(DestaqueClass Destaque)
		{
			try
			{
				return new DataAccess().Insert(Destaque, DESTAQUE.ID, TABELAS.DESTAQUE);
			}
			catch (Exception)
			{

				throw;
			}
		}
		public DestaqueClass SelectDestaqueByProductID(Int64 prodID)
		{
			try
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(DESTAQUE.PRODUTO_ID, prodID);

				var da = new DataAccess();

				List<DestaqueClass> lst = da.Select(new DestaqueClass(), TABELAS.DESTAQUE, new string[] { "*" }, parametros).toDestaqueClass();

				if (lst.Count > 0)
					return lst[0];
				else
					return null;
			}
			catch (Exception)
			{
				throw;
			}
		}
		public List<DestaqueClass> GetDestaques()
		{
			try
			{
				return new DataAccess().Select(new DestaqueClass(), TABELAS.DESTAQUE, new string[] { "*" }, null).toDestaqueClass();
			}
			catch (Exception)
			{
				throw;
			}
		}
		public void DeleteDestaques(int DestaqueID)
		{
			try
			{
				new DataAccess().Delete(TABELAS.DESTAQUE, DESTAQUE.ID, DestaqueID);
			}
			catch (Exception)
			{
				throw;
			}
		}
		public int DestaquesQuantidade()
		{
			try
			{
				return new DataAccess().GetNumberOfMatchingRows(new DestaqueClass(), TABELAS.DESTAQUE, null);
			}
			catch (Exception)
			{
				throw;
			}
		}
		#endregion
		#region Dimensão
		public Int64 InsertDimensao(DimensoesClass Dimensao)
		{
			return new DataAccess().Insert(Dimensao, DIMENSOES.ID, TABELAS.DIMENSOES);
		}
		public DimensoesClass SelectDimensao(long Dimensao_ID)
		{
			try
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(DIMENSOES.ID, Dimensao_ID); //Comparar a dimensao do produto, com a dimensao recebida no parametro. Tem de ser iguais


				var lst = new DataAccess().Select(new DimensoesClass(), TABELAS.DIMENSOES, new string[] { "*" }, parametros).toDimensoesClass();

				if (lst == null)
					return null;
				return lst[0];
			}
			catch (Exception)
			{
				throw;
			}
		}
		public void UpdateDimensao(DimensoesClass Dimensao)
		{
			Dictionary<string, object> set = new Dictionary<string, object>();
			parametros = new Dictionary<string, object>();

			set.Add(DIMENSOES.ID, Dimensao.ID);
			set.Add(DIMENSOES.PESO, Dimensao.Peso);
			parametros.Add(DIMENSOES.ID, Dimensao.ID);

			new DataAccess().Update(Dimensao, TABELAS.DIMENSOES, set, parametros);
		}
		#endregion
		#region Dividir
		public Int64 InsertDividir(DividirClass Dividir)
		{
			return new DataAccess().Insert(Dividir, DIVIDIR.ID, TABELAS.DIVIDIR);
		}
		public DividirClass SelectDividir(Int64 DividirID)
		{
			parametros = new Dictionary<string, object>();
			parametros.Add(DIVIDIR.ID, DividirID);

			return new DataAccess().Select(new DividirClass(), TABELAS.DIVIDIR, new string[] { "*" }, parametros).toDividirClass()[0];
		}
		public void UpdateDividir(DividirClass Dividir)
		{
			Dictionary<string, object> set = new Dictionary<string, object>();
			parametros = new Dictionary<string, object>();

			set.Add(DIVIDIR.JUROS, Dividir.Juros);
			set.Add(DIVIDIR.PARCELAS, Dividir.MaximoParcelas);

			parametros.Add(DIVIDIR.ID, Dividir.ID);

			new DataAccess().Update(Dividir, TABELAS.DIVIDIR, set, parametros);
		}
		#endregion
		#region Especificações
		public int InsertEspecificacao(EspecificacaoClass Especificacao)
		{
			return new DataAccess().Insert(Especificacao, ESPECIFICACAO.ID, TABELAS.ESPECIFICACAO);
		}
		public EspecificacaoClass SelectEspecificacao(Int64 EspecificacaoID)
		{
			parametros = new Dictionary<string, object>();
			parametros.Add(ESPECIFICACAO.ID, EspecificacaoID);

			return new DataAccess().Select(new EspecificacaoClass(), TABELAS.ESPECIFICACAO, new string[] { "*" }, parametros).toEspecificacaoClass()[0];
		}
		public EspecificacaoClass SelectEspecificacao(string CodigoProduto)
		{
			parametros = new Dictionary<string, object>();
			parametros.Add(ESPECIFICACAO.CODIGO_LOJA, CodigoProduto);

			var lst = new DataAccess().Select(new EspecificacaoClass(), TABELAS.ESPECIFICACAO, new string[] { "*" }, parametros).toEspecificacaoClass();

			if (lst == null)
				return null;
			else
				return lst[0];
		}
		public void UpdateEspecificacao(EspecificacaoClass Especificacao)
		{
			Dictionary<string, object> set = new Dictionary<string, object>();
			parametros = new Dictionary<string, object>();

			set.Add(ESPECIFICACAO.CODIGO_LOJA, Especificacao.CodigoLoja);
			set.Add(ESPECIFICACAO.COR, Especificacao.Cor);
			set.Add(ESPECIFICACAO.OBSERVACAO, Especificacao.Observacao);
			set.Add(ESPECIFICACAO.QUANTIDADE, Especificacao.Quantidade);
			set.Add(ESPECIFICACAO.TAMANHO, Especificacao.Tamanho);

			parametros.Add(ESPECIFICACAO.ID, Especificacao.ID);

			new DataAccess().Update(Especificacao, TABELAS.ESPECIFICACAO, set, parametros);
		}

		public List<EspecificacaoClass> GetEspecificacoes(Int64 ProdutoID)
		{
			try
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(ESPECIFICACAO.PRODUTO_ID, ProdutoID);
				return new DataAccess().Select(new EspecificacaoClass(), TABELAS.ESPECIFICACAO, new string[] { "*" }, parametros).toEspecificacaoClass();
			}
			catch (Exception)
			{

				throw;
			}
		}
		public void DeleteEspecificacao(Int64 EspecificacaoID)
		{
			try
			{
				new DataAccess().Delete(TABELAS.ESPECIFICACAO, ESPECIFICACAO.ID, EspecificacaoID);
			}
			catch (Exception)
			{

				throw;
			}
		}
		#endregion
		#region Fotos
		public int InsertFoto(FotosClass Fotos)
		{
			try
			{
				return new DataAccess().Insert(Fotos, FOTOS.ID, TABELAS.FOTOS);
			}
			catch (Exception)
			{
				throw;
			}
		}
		public FotosClass SelectFoto(Int64 FotoID)
		{
			try
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(FOTOS.ID, FotoID);

				return new DataAccess().Select(new FotosClass(), TABELAS.FOTOS, new string[] { "*" }, parametros).toFotosClass()[0];
			}
			catch (Exception)
			{

				throw;
			}
		}
		public List<FotosClass> SelectFotos(Int64 ProdutoID)
		{
			try
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(FOTOS.PRODUTO_ID, ProdutoID);

				return new DataAccess().Select(new FotosClass(), TABELAS.FOTOS, new string[] { "*" }, parametros).toFotosClass();
			}
			catch (Exception)
			{

				throw;
			}
		}
		public int GetQuantidadeFotos(Int64 ProdutoID)
		{
			parametros = new Dictionary<string, object>();
			parametros.Add(FOTOS.PRODUTO_ID, ProdutoID);

			return new DataAccess().GetNumberOfMatchingRows(new FotosClass(), TABELAS.FOTOS, parametros);
		}
		public void DeleteFoto(Int64 ID)
		{
			new DataAccess().Delete(TABELAS.FOTOS, FOTOS.ID, ID);
		}
		#endregion
		#region Marca
		public int InsertMarca(MarcaClass Marca)
		{
			try
			{
				return new DataAccess().Insert(Marca, MARCA.ID, TABELAS.MARCA);
			}
			catch (Exception)
			{
				throw;
			}
		}
		public MarcaClass SelectMarca(int MarcaID)
		{
			try
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(MARCA.ID, MarcaID);

				var lst = new DataAccess().Select(new MarcaClass(), TABELAS.MARCA, new string[] { "*" }, parametros).toMarcaClass();

				return lst[0];
			}
			catch (Exception)
			{

				throw;
			}
		}
		public List<MarcaClass> GetMarcas()
		{
			try
			{
				return new DataAccess().Select(new MarcaClass(), TABELAS.MARCA, new string[] { "*" }, null).toMarcaClass();
			}
			catch (Exception)
			{
				throw;
			}
		}
		public void UpdateMarca(MarcaClass Marca)
		{
			Dictionary<string, object> set = new Dictionary<string, object>();
			parametros = new Dictionary<string, object>();

			set.Add(MARCA.DESCRICAO, Marca.Descricao);

			parametros.Add(MARCA.ID, Marca.ID);

			new DataAccess().Update(Marca, TABELAS.MARCA, set, parametros);
		}
		public void DeleteMarcas(int MarcaID)
		{
			try
			{
				new DataAccess().Delete(TABELAS.MARCA, MARCA.ID, MarcaID);
			}
			catch (Exception)
			{

				throw;
			}
		}
		#endregion
		#region Produto
		public Int64 InsertProduto(ProdutoClass Produto)
		{
			return new DataAccess().Insert(Produto, PRODUTO.ID, TABELAS.PRODUTO);
		}
		public ProdutoClass SelectProduto(Int64 ProdutoID, bool CarregaMarca, bool CarregaCategoria)
		{
			try
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(PRODUTO.ID, ProdutoID);

				List<ProdutoClass> lstProdutos = new DataAccess().Select(new ProdutoClass(), TABELAS.PRODUTO, new string[] { "*" }, parametros).toProdutoClass();

				if (lstProdutos == null)
					return null;

				ProdutoClass produto = lstProdutos[0];

				if (CarregaMarca)
				{
					produto.Marca = new MarcaClass();
					produto.Marca = SelectMarca(produto.MarcaID);
				}

				if (CarregaCategoria)
				{
					produto.Categoria = new CategoriaClass();
					produto.Categoria = SelectCategoria(produto.CategoriaID);
				}

				return produto;
			}
			catch (Exception)
			{

				throw;
			}
		}
		public List<ProdutoClass> GetProdutos(int _skip, int _take, Ordenacao _ordenacao, string _filtro, out int _numProdutos)
		{
			try
			{
				List<ProdutoClass> lstProdutos = new List<ProdutoClass>();

				if (_filtro.Equals(string.Empty))
					lstProdutos = new DataAccess().Select(new ProdutoClass(), TABELAS.PRODUTO, new string[] { "*" }, null).toProdutoClass();
				else
				{
					List<MarcaClass> lstMarcas = new List<MarcaClass>();
					lstMarcas = new Connection().Select(string.Format("select * from {0} where {1} like '%{2}%'", TABELAS.MARCA, MARCA.DESCRICAO, _filtro)).toMarcaClass();

					List<CategoriaClass> lstCategorias = new List<CategoriaClass>();
					lstCategorias = new Connection().Select(string.Format("select * from {0} where {1} like '%{2}%'", TABELAS.CATEGORIA, CATEGORIA.DESCRICAO, _filtro)).toCategoriaClass();

					if (lstMarcas != null)
						lstMarcas.ForEach(a => lstProdutos.AddRange(
											new DataAccess().Select(
												new ProdutoClass(),
												TABELAS.PRODUTO,
												new string[] { "*" },
												new Dictionary<string, object>() { { PRODUTO.MARCA_ID, a.ID } }).toProdutoClass()));

					if (lstCategorias != null)
					{
						bool found = false;
						foreach (CategoriaClass Categoria in lstCategorias)
						{
							List<ProdutoClass> prodCat = new DataAccess().Select(
												new ProdutoClass(),
												TABELAS.PRODUTO,
												new string[] { "*" },
												new Dictionary<string, object>() { { PRODUTO.CATEGORIA_ID, Categoria.ID } }).toProdutoClass();
							if (prodCat != null)
							{
								lstProdutos.AddRange(prodCat);
								found = true;
							}
						}

						if(!found)
						{
							foreach (CategoriaClass Categoria in lstCategorias)
							{
								List<ProdutoClass> prodCat = new DataAccess().Select(
													new ProdutoClass(),
													TABELAS.PRODUTO,
													new string[] { "*" },
													new Dictionary<string, object>() { { PRODUTO.CATEGORIA_SECUNDARIA_ID, Categoria.ID } }).toProdutoClass();
								if (prodCat != null)
									lstProdutos.AddRange(prodCat);
							}
						}
					}
				}

				_numProdutos = lstProdutos.Count();

				if ((lstProdutos == null) || (_numProdutos == 0))
					return lstProdutos;

				switch (_ordenacao)
				{
					case Ordenacao.Newest:
						lstProdutos = lstProdutos.OrderBy(a => a.Data).Skip(_skip).Take(_take).ToList();
						break;
					case Ordenacao.Name:
						lstProdutos = lstProdutos.OrderBy(a => a.Modelo).Skip(_skip).Take(_take).ToList();
						break;
					case Ordenacao.Cheaper:
						lstProdutos = lstProdutos.OrderBy(a => a.Preco).Skip(_skip).Take(_take).ToList();
						break;
					case Ordenacao.Expensive:
						lstProdutos = lstProdutos.OrderByDescending(a => a.Preco).Skip(_skip).Take(_take).ToList();
						break;
					default:
						break;
				}

				return lstProdutos;
			}
			catch (Exception)
			{
				throw;
			}
		}
		public List<ProdutoClass> GetProdutosByCodigo(int _skip, int _take, Ordenacao _ordenacao, string _filtro, out int _numProdutos)
		{
			List<ProdutoClass> lstProdutos = new List<ProdutoClass>();

			if (_filtro.Equals(string.Empty))
				lstProdutos = new DataAccess().Select(new ProdutoClass(), TABELAS.PRODUTO, new string[] { "*" }, null).toProdutoClass();
			else
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(ESPECIFICACAO.CODIGO_LOJA, _filtro);
				List<EspecificacaoClass> lstEspecificacao =
					new Connection().Select(string.Format("select * from {0} where {1} like '%{2}%'", TABELAS.ESPECIFICACAO, ESPECIFICACAO.CODIGO_LOJA, _filtro)).toEspecificacaoClass();

				_numProdutos = 0;

				if (lstEspecificacao == null)
					return null;

				foreach (EspecificacaoClass Especificacao in lstEspecificacao)
				{
					Dictionary<string, object> dic = new Dictionary<string, object>();
					dic.Add(PRODUTO.ID, Especificacao.ProdutoID);

					List<ProdutoClass> prods = new List<ProdutoClass>();
					prods = new DataAccess().Select(new ProdutoClass(), TABELAS.PRODUTO, new string[] { "*" }, dic).toProdutoClass();
					if (prods != null)
						lstProdutos.AddRange(prods);
				}
			}

			_numProdutos = lstProdutos.Count();

			if (lstProdutos == null)
				throw new ApplicationException("Nenhum produto encontrado!");

			switch (_ordenacao)
			{
				case Ordenacao.Newest:
					lstProdutos = lstProdutos.OrderBy(a => a.Data).Skip(_skip).Take(_take).ToList();
					break;
				case Ordenacao.Name:
					lstProdutos = lstProdutos.OrderBy(a => a.Modelo).Skip(_skip).Take(_take).ToList();
					break;
				case Ordenacao.Cheaper:
					lstProdutos = lstProdutos.OrderBy(a => a.Preco).Skip(_skip).Take(_take).ToList();
					break;
				case Ordenacao.Expensive:
					lstProdutos = lstProdutos.OrderByDescending(a => a.Preco).Skip(_skip).Take(_take).ToList();
					break;
				default:
					break;
			}

			return lstProdutos;
		}
		public List<ProdutoClass> GetProdutosByMaster(int _skip, int _take, Ordenacao _ordenacao, string _filtro, out int _numProdutos)
		{
			try
			{
				List<ProdutoClass> lstProdutos = new List<ProdutoClass>();
				List<CategoriaMasterClass> lstCatMaster = new List<CategoriaMasterClass>();
				lstCatMaster = new Connection().Select(string.Format("select * from {0} where {1} like '%{2}%'", TABELAS.CATEGORIA_MASTER, CATEGORIA_MASTER.DESCRICAO, _filtro)).toCategoriaMasterClass();

				if (lstCatMaster != null)
					lstCatMaster.ForEach(a => lstProdutos.AddRange(
										new DataAccess().Select(
											new ProdutoClass(),
											TABELAS.PRODUTO,
											new string[] { "*" },
											new Dictionary<string, object>() { { PRODUTO.CATEGORIAMASTER_ID, a.ID } }).toProdutoClass()));

				_numProdutos = lstProdutos.Count();

				if ((lstProdutos == null) || (_numProdutos == 0))
					throw new ApplicationException("Nenhum produto encontrado!");

				switch (_ordenacao)
				{
					case Ordenacao.Newest:
						lstProdutos = lstProdutos.OrderBy(a => a.Data).Skip(_skip).Take(_take).ToList();
						break;
					case Ordenacao.Name:
						lstProdutos = lstProdutos.OrderBy(a => a.Modelo).Skip(_skip).Take(_take).ToList();
						break;
					case Ordenacao.Cheaper:
						lstProdutos = lstProdutos.OrderBy(a => a.Preco).Skip(_skip).Take(_take).ToList();
						break;
					case Ordenacao.Expensive:
						lstProdutos = lstProdutos.OrderByDescending(a => a.Preco).Skip(_skip).Take(_take).ToList();
						break;
					default:
						break;
				}

				return lstProdutos;
			}
			catch (Exception)
			{
				throw;
			}
		}
		public void UpdateProduto(ProdutoClass Produto)
		{
			Dictionary<string, object> set = new Dictionary<string, object>();
			parametros = new Dictionary<string, object>();

			set.Add(PRODUTO.CATEGORIA_ID, Produto.CategoriaID);
			set.Add(PRODUTO.CATEGORIA_SECUNDARIA_ID, Produto.CategoriaSecundariaID);
			set.Add(PRODUTO.CATEGORIAMASTER_ID, Produto.CategoriaMasterID);
			set.Add(PRODUTO.DATA, Produto.Data);
			set.Add(PRODUTO.DESCRICAO, Produto.Descricao);
			set.Add(PRODUTO.DIMENSOES_ID, Produto.DimensoesID);
			set.Add(PRODUTO.DIVIDIR_ID, Produto.DividirID);
			set.Add(PRODUTO.FOTO, Produto.Foto);
			set.Add(PRODUTO.MARCA_ID, Produto.MarcaID);
			set.Add(PRODUTO.MODELO, Produto.Modelo);
			set.Add(PRODUTO.PRECO, Produto.Preco);

			parametros.Add(PRODUTO.ID, Produto.ID);

			new DataAccess().Update(Produto, TABELAS.PRODUTO, set, parametros);
		}
		public void DeleteProduto(Int64 prodID)
		{
			try
			{
				new DataAccess().Delete(TABELAS.PRODUTO, PRODUTO.ID, prodID);
			}
			catch (Exception)
			{
				throw;
			}
		}
		public bool isDestaque(ProdutoClass Produto)
		{
			parametros = new Dictionary<string,object>();
			parametros.Add(DESTAQUE.PRODUTO_ID, Produto.ID);

			var lst = new DataAccess().Select(new DestaqueClass(), TABELAS.DESTAQUE, new string[] { "*" }, parametros).toDestaqueClass();
			if(lst == null)
				return false;
			
			return lst.Count > 0;
		}
		#endregion
		#region Promoção
		public PromocaoClass SelectPromocao(Int64 ProdutoID)
		{
			try
			{
				parametros = new Dictionary<string, object>();
				parametros.Add(PROMOCAO.PRODUTO_ID, ProdutoID);

				List<PromocaoClass> promo = new DataAccess().Select(new PromocaoClass(), TABELAS.PROMOCAO, new string[] { "*" }, parametros).toPromocaoClass();

				if (promo != null)
					return promo[0];
				else
					return null;
			}
			catch (Exception)
			{
				throw;
			}
		}
		#endregion
		#region Views
		public int InsertView(ViewsClass View)
		{
			return new DataAccess().Insert(View, VIEWS.ID, TABELAS.VIEWS);
		}
		#endregion
	}
}
